package sql.parser;

import java.util.ArrayList;
import java.util.List;

import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.create.schema.CreateSchema;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
import session.Session;
import sql.executor.SQLExecutor;
import storage.manager.DatabaseManager;

/**
 * SQLParser 负责解析 SQL 语句并调用 SQLExecutor 进行执行。
 * - 支持解析 INSERT、SELECT、DELETE、UPDATE 等基本 SQL 语句。
 * - 对于不同类型的 SQL，选择适当的 SQLExecutor 方法执行。
 */
public class SQLParser {

    /**
     * 执行不需要返回数据的 SQL 语句，例如 CREATE、INSERT、DELETE、UPDATE、DROP。
     *
     * @param sql SQL 语句
     * @return int 执行状态码：1 表示成功，0 表示失败
     */
    public static int executeUpdate(String sql) {
        try {
            String upperSql = sql.toUpperCase().trim();

            // 处理 GRANT 语句: GRANT ACCESS ON DATABASE ownerName.dbName TO userName;
            if (upperSql.startsWith("GRANT ACCESS ON DATABASE")) {
                String[] parts = sql.trim().split("\\s+");
                // Expected format: GRANT ACCESS ON DATABASE <owner.dbName> TO <userName>;
                if (parts.length >= 7 && parts[1].equalsIgnoreCase("ACCESS") && parts[2].equalsIgnoreCase("ON") && parts[3].equalsIgnoreCase("DATABASE") && parts[5].equalsIgnoreCase("TO")) {
                    String ownerAndDbName = parts[4];
                    String userName = parts[6].replace(";", "");

                    String[] dbIdentifierParts = ownerAndDbName.split("\\.");
                    if (dbIdentifierParts.length == 2) {
                        String ownerName = dbIdentifierParts[0];
                        String dbName = dbIdentifierParts[1];
                        return SQLExecutor.executeGrantPrivilege(ownerName, dbName, userName);
                    } else {
                        // Fallback or error for old format (dbName only) - for now, we require owner.dbName
                        System.err.println("❌ GRANT 语法错误。数据库名需使用 'ownerName.dbName' 格式。");
                        return 0;
                    }
                } else {
                    System.err.println("❌ GRANT 语法错误。预期格式: GRANT ACCESS ON DATABASE <ownerName.dbName> TO <userName>;");
                    return 0;
                }
            }

            // 处理 REVOKE 语句: REVOKE ACCESS ON DATABASE ownerName.dbName FROM userName;
            if (upperSql.startsWith("REVOKE ACCESS ON DATABASE")) {
                String[] parts = sql.trim().split("\\s+");
                // Expected format: REVOKE ACCESS ON DATABASE <owner.dbName> FROM <userName>;
                if (parts.length >= 7 && parts[1].equalsIgnoreCase("ACCESS") && parts[2].equalsIgnoreCase("ON") && parts[3].equalsIgnoreCase("DATABASE") && parts[5].equalsIgnoreCase("FROM")) {
                    String ownerAndDbName = parts[4];
                    String userName = parts[6].replace(";", "");

                    String[] dbIdentifierParts = ownerAndDbName.split("\\.");
                    if (dbIdentifierParts.length == 2) {
                        String ownerName = dbIdentifierParts[0];
                        String dbName = dbIdentifierParts[1];
                        return SQLExecutor.executeRevokePrivilege(ownerName, dbName, userName);
                    } else {
                        System.err.println("❌ REVOKE 语法错误。数据库名需使用 'ownerName.dbName' 格式。");
                        return 0;
                    }
                } else {
                    System.err.println("❌ REVOKE 语法错误。预期格式: REVOKE ACCESS ON DATABASE <ownerName.dbName> FROM <userName>;");
                    return 0;
                }
            }

            // 特殊处理 SHOW TABLES 命令
            if (upperSql.startsWith("SHOW TABLES")) {
                Session currentSession = Session.getCurrentSession();
                String currentDbName = null;
                String currentDbOwner = null;
                if (currentSession != null) {
                    currentDbName = currentSession.getCurrentDatabaseName();
                    currentDbOwner = currentSession.getCurrentDatabaseOwnerName();
                }
                
                if (currentDbName == null || currentDbName.isEmpty() || currentDbOwner == null || currentDbOwner.isEmpty()) {
                    System.err.println("错误：没有选择数据库或所有者信息不完整。请使用 USE DATABASE 命令选择一个数据库。");
                    return 0;
                }
                DatabaseManager.showTables(currentDbOwner, currentDbName);
                return 1;
            }

            // 特殊处理 DELETE DATABASE 命令 - 更新为 ownerName.dbName
            if (upperSql.startsWith("DELETE DATABASE")) {
                String[] parts = sql.trim().split("\\s+");
                if (parts.length == 3) {
                    String ownerAndDbName = parts[2].replace(";", "");
                    String[] dbIdentifierParts = ownerAndDbName.split("\\.");
                    if (dbIdentifierParts.length == 2) {
                        String ownerName = dbIdentifierParts[0];
                        String dbName = dbIdentifierParts[1];
                        return SQLExecutor.executeDeleteDatabase(ownerName, dbName);
                    } else {
                        System.err.println("❌ DELETE DATABASE 语法错误。数据库名需使用 'ownerName.dbName' 格式。");
                        return 0;
                    }
                } else {
                    System.err.println("❌ DELETE DATABASE 语法错误。预期格式: DELETE DATABASE <ownerName.dbName>;");
                    return 0;
                }
            }

            // 特殊处理DESCRIBE/DESC表结构命令
            if (upperSql.startsWith("DESCRIBE ") || upperSql.startsWith("DESC ")) {
                // 获取表名
                String[] parts = sql.split("\\s+");
                if (parts.length > 1) {
                    String tableName = parts[1].replace(";", "").trim();
                    Session currentSession = Session.getCurrentSession();
                    String currentDbName = null;
                    String currentDbOwner = null;
                    if (currentSession != null) {
                        currentDbName = currentSession.getCurrentDatabaseName();
                        currentDbOwner = currentSession.getCurrentDatabaseOwnerName();
                    }
                    if (currentDbName == null || currentDbName.isEmpty() || currentDbOwner == null || currentDbOwner.isEmpty()) {
                        System.err.println("错误：没有选择数据库或所有者信息不完整。请使用 USE DATABASE 命令。 (DESCRIBE)");
                        return 0;
                    }
                    DatabaseManager.showTableInfo(tableName, currentDbOwner, currentDbName);
                    return 1;
                } else {
                    System.err.println("❌ 语法错误: 请指定表名 (DESCRIBE table_name)");
                    return 0;
                }
            }

            // 移除SQL语句末尾的分号，以避免JSqlParser解析错误
            String cleanSql = sql.trim();
            if (cleanSql.endsWith(";")) {
                cleanSql = cleanSql.substring(0, cleanSql.length() - 1);
                System.out.println("[DEBUG SQLParser] 移除末尾分号，处理后的SQL: " + cleanSql);
            }
            
            Statement statement = CCJSqlParserUtil.parse(cleanSql);

            if (statement != null) {
                System.out.println("[DEBUG SQLParser] Parsed statement type: " + statement.getClass().getName());
            } else {
                System.out.println("[DEBUG SQLParser] Parsing returned null statement.");
            }

            if (statement instanceof CreateSchema) {
                CreateSchema createSchemaStmt = (CreateSchema) statement;
                String newDbName = createSchemaStmt.getSchemaName();
                int result = SQLExecutor.executeCreateDatabase(createSchemaStmt);
                // 创建成功后自动切换上下文
                if (result == 1) {
                    Session currentSession = Session.getCurrentSession();
                    String creator = null;
                    if (currentSession != null) {
                        creator = currentSession.getUsername(); 
                    }
                    if (creator != null && newDbName != null && !newDbName.isEmpty()) {
                         // The DatabaseManager.setCurrentDatabase is primarily for DatabaseManager's internal static context
                         // The actual session context (currentDatabaseName, currentDatabaseOwnerName) 
                         // is set by Session.handleUseDatabase or Session.setCurrentDatabase directly.
                         // If createDatabase implies an immediate USE, that should be handled by Session layer
                         // or by having executeCreateDatabase also perform the USE logic via Session.
                         // For now, we update DatabaseManager's static context if it relies on it.
                        DatabaseManager.setCurrentDatabase(creator, newDbName); 
                        System.out.println("[SQLParser] DatabaseManager static context set to: " + creator + "." + newDbName);
                        // To make the *session* also use this new DB, Session.handleCreateDatabase should call Session.setCurrentDatabase.
                    } else {
                        System.err.println("[SQLParser] 未能自动设置当前数据库上下文：创建者或数据库名未知。");
                    }
                }
                return result;
            } else if (statement instanceof UseStatement) {
                // This branch is likely not hit by Session.executeUpdate for USE statements due to custom handling.
                // If hit, JSqlParser's UseStatement only has dbName. Assume current user is owner.
                UseStatement useStmt = (UseStatement) statement;
                String dbName = useStmt.getName();
                Session currentSession = Session.getCurrentSession();
                String ownerName = null;
                if (currentSession != null) {
                    ownerName = currentSession.getUsername();
                }
                if (ownerName == null || dbName == null || dbName.isEmpty()){
                    System.err.println("❌ USE DATABASE 失败: 无法确定所有者或数据库名。");
                    return 0;
                }
                // SQLExecutor.executeUseDatabase should internally call Session.setCurrentDatabase(ownerName, dbName)
                // or Session.handleUseDatabase(ownerName, dbName)
                // For now, assume SQLExecutor.executeUseDatabase handles the owner context correctly if it receives a UseStatement object.
                // The current SQLExecutor.executeUseDatabase(UseStatement) might need adjustment.
                System.out.println("[SQLParser] Info: JSqlParser UseStatement branch hit for DB: " + dbName + ". Assuming owner: " + ownerName);
                return SQLExecutor.executeUseDatabase(useStmt); // This executeUseDatabase needs to be owner-aware
            } else if (statement instanceof CreateTable) {
                return SQLExecutor.executeCreateTable((CreateTable) statement);
            } else if (statement instanceof Drop) {
                // For DROP commands, we might need custom parsing if it's DROP DATABASE
                // to enforce ownerName.dbName, similar to DELETE DATABASE.
                Drop dropStmt = (Drop) statement;
                if ("DATABASE".equalsIgnoreCase(dropStmt.getType())) {
                    // Custom parsing for DROP DATABASE ownerName.dbName
                    // We need to get the raw SQL for this, as JSqlParser's Drop object might not easily give owner.db
                    // This is a bit of a hack. A more robust way would be to check raw sql string *before* parsing with JSqlParser
                    // or extend JSqlParser if possible.
                    // Assuming sql variable holds the original command string
                    String[] parts = sql.trim().split("\\s+"); // sql is the input to executeUpdate
                    if (parts.length == 3 && parts[0].equalsIgnoreCase("DROP") && parts[1].equalsIgnoreCase("DATABASE")) {
                        String ownerAndDbName = parts[2].replace(";", "");
                        String[] dbIdentifierParts = ownerAndDbName.split("\\.");
                        if (dbIdentifierParts.length == 2) {
                            String ownerName = dbIdentifierParts[0];
                            String dbName = dbIdentifierParts[1];
                            // Call a modified executeDropDatabase or directly SQLExecutor.executeDeleteDatabase if the logic is identical
                            return SQLExecutor.executeDropDatabase(ownerName, dbName); // Needs new method in SQLExecutor
                        } else {
                            System.err.println("❌ DROP DATABASE 语法错误。数据库名需使用 'ownerName.dbName' 格式。");
                            return 0;
                        }
                    } else {
                        System.err.println("❌ DROP DATABASE 语法错误。预期格式: DROP DATABASE <ownerName.dbName>;");
                        return 0;
                    }
                } else { // For DROP TABLE, DROP INDEX etc., JSqlParser is fine
                    return SQLExecutor.executeDrop(dropStmt);
                }
            }else if(statement instanceof Alter) {
                return SQLExecutor.executeAlter((Alter) statement);
            } else if (statement instanceof Insert) {
                return SQLExecutor.executeInsert((Insert) statement);
            } else if (statement instanceof Delete) {
                return SQLExecutor.executeDelete((Delete) statement);
            } else if (statement instanceof Update) {
                return SQLExecutor.executeUpdate((Update) statement);
            } else {
                System.out.println("❗ 不支持的 SQL 语句类型");
                return 0;
            }
        } catch (Exception e) {
            System.err.println("❌ SQL 解析或执行失败: " + e.getMessage());
            return -1;
        }
    }

    /**
     * 执行需要返回数据的 SQL 语句，例如 SELECT。
     *
     * @param sql SQL 语句
     * @return List<String [ ]> 查询结果，每一行为一个数据数组
     */
    public static List<String[]> executeQuery(String sql) {
        try {
            // 移除SQL语句末尾的分号，以避免JSqlParser解析错误
            String cleanSql = sql.trim();
            if (cleanSql.endsWith(";")) {
                cleanSql = cleanSql.substring(0, cleanSql.length() - 1);
                System.out.println("[DEBUG SQLParser] 移除末尾分号，处理后的SQL: " + cleanSql);
            }
            
            Statement statement = CCJSqlParserUtil.parse(cleanSql);

            if (statement instanceof Select) {
                return SQLExecutor.executeSelect((Select) statement);
            } else {
                System.out.println("❗ 该 SQL 语句不支持数据查询");
                List<String[]> errorResult = new ArrayList<>();
                errorResult.add(new String[]{"❗ 该 SQL 语句不支持数据查询"});
                return errorResult;
            }
        } catch (Exception e) {
            System.err.println("❌ SQL 解析或执行失败: " + e.getMessage());
            List<String[]> errorResult = new ArrayList<>();
            errorResult.add(new String[]{"❌ SQL解析或执行异常: " + e.getMessage()});
            return errorResult;
        }
    }
}

